package com.emeraldparser.util;

import static com.google.common.collect.Collections2.*;
import static com.emeraldparser.util.Collections3.*;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Table;

public abstract class CollectionBasedTable<E, R, C, V> implements Table<R, C, V> {

	protected abstract Collection<E> collection();

	protected abstract Collection<Cell<R, C, V>> cells();

	@Override
	public Set<Cell<R, C, V>> cellSet() {
		return set(cells());
	}

	protected abstract R rowKey(E element);

	protected abstract C columnKey(E element);

	protected abstract V value(E element);

	protected abstract V value(Object rowKey, Object columnKey, Collection<E> filteredElements);

	private Function<E, R> rowKeyFunction() {
		return new Function<E, R>() {
			@Override
			public R apply(E element) {
				return rowKey(element);
			}
		};
	}

	private Predicate<E> rowKeyPredicate(final Object rowKey) {
		return new Predicate<E>() {
			@Override
			public boolean apply(E element) {
				return Objects.equal(rowKey, rowKey(element));
			}
		};
	}

	private Function<E, C> columnKeyFunction() {
		return new Function<E, C>() {
			@Override
			public C apply(E element) {
				return columnKey(element);
			}
		};
	}

	private Predicate<E> columnKeyPredicate(final Object columnKey) {
		return new Predicate<E>() {
			@Override
			public boolean apply(E element) {
				return Objects.equal(columnKey, columnKey(element));
			}
		};
	}

	private Function<E, V> valueFunction() {
		return new Function<E, V>() {
			@Override
			public V apply(E element) {
				return value(element);
			}
		};
	}

	private Predicate<E> cellPredicate(final Object rowKey, final Object columnKey) {
		return new Predicate<E>() {
			@Override
			public boolean apply(E element) {
				return Objects.equal(rowKey, rowKey(element))
				    && Objects.equal(columnKey, columnKey(element));
			}
		};
	}

	@Override
	public boolean contains(Object rowKey, Object columnKey) {
		return Iterables.any(collection(), cellPredicate(rowKey, columnKey));
	}

	@Override
	public boolean containsRow(Object rowKey) {
		return Iterables.any(collection(), rowKeyPredicate(rowKey));
	}

	@Override
	public boolean containsColumn(Object columnKey) {
		return Iterables.any(collection(), columnKeyPredicate(columnKey));
	}

	@Override
	public boolean containsValue(Object value) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public V get(Object rowKey, Object columnKey) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isEmpty() {
		return cellSet().isEmpty();
	}

	@Override
	public int size() {
		return cellSet().size();
	}

	@Override
	public void clear() {
		cellSet().clear();
	}

	@Override
	public V put(R rowKey, C columnKey, V value) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public V remove(Object rowKey, Object columnKey) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Map<C, V> row(R rowKey) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Map<R, V> column(C columnKey) {
		// TODO Auto-generated method stub
		return null;
	}

	private Collection<R> rowKeys() {
		return transform(collection(), rowKeyFunction());
	}

	@Override
	public Set<R> rowKeySet() {
		return set(rowKeys());
	}

	private Collection<C> columnKeys() {
		return transform(collection(), columnKeyFunction());
	}

	@Override
	public Set<C> columnKeySet() {
		return set(columnKeys());
	}

	@Override
	public Collection<V> values() {
		return transform(collection(), valueFunction());
	}

	@Override
	public Map<R, Map<C, V>> rowMap() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Map<C, Map<R, V>> columnMap() {
		// TODO Auto-generated method stub
		return null;
	}

}
